package com.weiai.wedding.dao;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.Parameter;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import com.weiai.wedding.util.ConUtils;
import com.weiai.wedding.util.Pagination;

/**
 * 获取分页方法
 * 
 * @author wangweiheng
 * 
 * @param <T>
 */
@Component
public class BaseQueryDao<T> {
	@PersistenceContext
	private EntityManager em;

	public Pagination<T> getPage(CriteriaQuery<T> query, Pagination<T> page,
			Class c, Predicate[] predicates) {
		CriteriaBuilder builder = em.getCriteriaBuilder();

		Query createQuery = em.createQuery(query);
		createQuery.setFirstResult(page.getFirstResult());
		createQuery.setMaxResults(page.getPageSize());
		CriteriaQuery<Long> cq = builder.createQuery(Long.class);
		Root<T> from = cq.from(c);
		cq.select(builder.count(from));
		cq.where(predicates);
		Long singleResult = em.createQuery(cq).getSingleResult();
		List<T> resultList = createQuery.getResultList();
		page.setTotalCount(singleResult);
		page.setDatas(resultList);
		page.setTotalPage();
		return page;
	}

	public void createOrderBy(CriteriaQuery<T> query, CriteriaBuilder builder,
			Root<T> root, Pagination<T> page) {
		String orderby = page.getOrderBy();
		String sort = page.getSort();
		Order desc = null;
		if ("desc".equals(sort)) {
			desc = builder.desc(root.get(orderby));
		} else {
			desc = builder.asc(root.get(orderby));
		}
		query.orderBy(desc);
	}

	public int update(Class<T> clazz, Map<String, Object> objMap, String id) {
		String entityName=clazz.getSimpleName();
		if (StringUtils.isNotBlank(id) && objMap != null && objMap.size() > 0) {
			StringBuffer queryStr = new StringBuffer("UPDATE " + entityName
					+ " SET");

			Iterator<Entry<String, Object>> iter = objMap.entrySet().iterator();
			while (iter.hasNext()) {
				Map.Entry<String, Object> entry = (Map.Entry<String, Object>) iter.next();
				Field field=null;
				Method method=null;
				try {
					field=clazz.getDeclaredField(entry.getKey());
				} catch (Exception e) {e.printStackTrace();}
				try {
					 PropertyDescriptor pd = new PropertyDescriptor(entry.getKey(), clazz);
					method=pd.getReadMethod();
				} catch (Exception e) {}
				if (entry.getValue() != null
						&& !"id".equalsIgnoreCase(entry.getKey())
						&& field!=null&&!field.isAnnotationPresent(Transient.class)
						&& method!=null&&!method.isAnnotationPresent(Transient.class)) {
					
							queryStr.append(" " + entry.getKey() + "=:"
									+ entry.getKey() + ",");
				}
			}

			queryStr.deleteCharAt(queryStr.length() - 1);
			queryStr.append(" WHERE id=:id ");

			Query query = em.createQuery(queryStr.toString());
			query.setParameter("id", id);

			Iterator<Entry<String, Object>> t = objMap.entrySet().iterator();
			while (t.hasNext()) {
				Map.Entry<String, Object> entry = (Map.Entry<String, Object>) t.next();
				Field field=null;
				Method method=null;
				try {
					field=clazz.getDeclaredField(entry.getKey());
				} catch (Exception e) {}
				
				try {
					 PropertyDescriptor pd = new PropertyDescriptor(entry.getKey(), clazz);
						method=pd.getReadMethod();
				} catch (Exception e) {}
				
				if (entry.getValue() != null
						&& !"id".equalsIgnoreCase(entry.getKey())
						&& field!=null&&!field.isAnnotationPresent(Transient.class)
						&& method!=null&&!method.isAnnotationPresent(Transient.class)) {
					
							Object parameterValue=entry.getValue();
							Parameter<?> parameter=query.getParameter(entry.getKey());
							if(parameter!=null&&parameter.getParameterType().equals(Date.class)){
								parameterValue=ConUtils.parseDate(String.valueOf(parameterValue));
							}
							query.setParameter(entry.getKey(),parameterValue);
				}
			}

			return query.executeUpdate();
		}
		return 0;
	}
//	public int update(Class<T> class1, Map<String, Object> modelMap,
//			String id) {
//		int i=this.update(class1.getSimpleName(), modelMap, id);
//		return i;
//	}
}
